home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Practical Algorithms for Image Analysis
/
Practical Algorithms for Image Analysis.iso
/
LIBIP
/
PMOM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1999-09-11
|
10KB
|
346 lines
/*
* pmom.c P(oly)MOM(ents)
*
* Practical Algorithms for Image Analysis
*
* Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "ip.h"
#define DENT_CUTOFF 0.001
#define TANGENT_LIMIT 1.0e06 /* indicates vertical axis */
#define MU11_EPS 5.0e03 /* indicates alignment with axes */
#define ZERO 0.0
#define FABS(a) ((a) > ZERO ? (a) : - (a))
#define SQR(a) ( (a)*(a) )
#define ON 1
#define OFF 0
#define SAVE_MOMENTS ON
#define DEBUG
#define CEN_DEBUG
#define SHOW_VERT
/*
* poly_moments()
* DESCRIPTION:
* poly_moments computes centroid, central moments, principal axes and
* first two moment invariants
* the centroid position is marked with a cross
* the principle axis directions are plotted
* ARGUMENTS:
* nv(long) number of vertices in polygon
* v(struct spoint *) pointer to struct containing the vertices
* moments(float *) pointer to array of floats to hold calculated moments
* imgIO(Image *) pointer to Image struct (see tiffimage.h)
* value(int) pixel value to use for plotting
* RETURN VALUE:
* (struct spoint *) that contains the centroid value
*/
struct spoint *
poly_moments (long nv, struct spoint *v, float *moments, Image * imgIO, int value)
{
int i, i_max, i_min;
int nvpp;
int size = 30;
int circle = 0, horizontal = 0, vertical = 0;
double ximm, xi, yimm, yi;
double d_xy, d_min, d_max;
double m00, m00_sum;
double m10, m10_sum, m01, m01_sum, m11, m11_sum;
double m20, m20_sum, m02, m02_sum;
double mu, mu11, mu20, mu02, dent;
double musq, phi_1, phi_2;
double rad_gyr;
double tg_tth, tg_th1, tg_th2, sq_root;
double mu02_div_mu20, mu11mu20_sign;
double x_major, y_major, x_minor, y_minor;
int quad_IV = OFF, quad_I = OFF;
static struct spoint *pvc, vc;
int color_index = 191;
pvc = &vc;
#ifdef SHOW_VERT
printf ("\n...PMOM: vertex coordinates\n");
for (i = 0; i < (int) nv; i++)
printf ("...%d: (%3d, %3d)\n", i, (v + i)->x, (v + i)->y);
#endif
/*
* compute moments
* refs:
* Hu, IRE Trans. Inf. Theory, IT-8, 179-187 (1962)
* Seul, Sammon and Monar, Rev. Sci. Instr. 62, 784-792 (1991)
*/
m00 = m10 = m01 = 0.0;
m11 = m20 = m02 = 0.0;
nvpp = (int) nv + 1;
for (i = 1; i < nvpp; i++) {
ximm = (double) (v + i - 1)->x;
xi = (double) (v + i)->x;
yimm = (double) (v + i - 1)->y;
yi = (double) (v + i)->y;
m00_sum = 0.5 * (yi * ximm - xi * yimm);
m00 += m00_sum;
m10_sum = 0.5 * (xi + ximm) * m00_sum;
m10_sum -= 0.5 * ((yi - yimm) * (xi * xi + xi * ximm + ximm * ximm) / 6.0);
m10 += m10_sum;
m01_sum = 0.5 * (yi + yimm) * m00_sum;
m01_sum += 0.5 * ((xi - ximm) * (yi * yi + yi * yimm + yimm * yimm) / 6.0);
m01 += m01_sum;
m11_sum = 0.5 * m00_sum;
m11 += m11_sum * (2.0 * xi * yi + ximm * yi + xi * yimm + 2.0 * ximm * yimm) / 6.0;
m20_sum = m00_sum * (xi * xi + xi * ximm + ximm * ximm) / 3.0;
m20_sum -= 0.5 * (yi - yimm) * (xi * xi * xi + xi * xi * ximm + xi * ximm * ximm + ximm * ximm * ximm) / 6.0;
m20 += m20_sum;
m02_sum = m00_sum * (yi * yi + yi * yimm + yimm * yimm) / 3.0;
m02_sum += 0.5 * (xi - ximm) * (yi * yi * yi + yi * yi * yimm + yi * yimm * yimm + yimm * yimm * yimm) / 6.0;
m02 += m02_sum;
}
printf ("\nmoments:\n");
printf ("...m00 = %lf\n", m00);
printf ("...m10 = %lf m01 = %lf\n", m10, m01);
printf ("...m11 = %lf m20 = %lf m02 = %lf\n", m11, m20, m02);
/*
* correct sign of raw moments if necessary
* ( -->negative moments are obtained from Zahn's representation
* of an 'inner' boundary, traversed in CCW sense)
*/
if (SIGN (m00) < ZERO) {
m00 *= -1.0;
m10 *= -1.0;
m01 *= -1.0;
m11 *= -1.0;
m20 *= -1.0;
m02 *= -1.0;
}
/*
* centroid
*/
pvc->x = (int) (m10 / m00);
pvc->y = (int) (m01 / m00);
#ifdef CEN_DEBUG
printf ("\nPOLY_MOMENT: centroid pos: (%3d, %3d)\n", pvc->x, pvc->y);
#endif
/*
* mark centroid position with a cross
*/
draw_cross (pvc->x, pvc->y, size, imgIO, value);
/*
* find curvature points closest to and farthest from the centroid
*/
i_max = i_min = 0;
d_max = 0.0;
d_min = 1000.0;
for (i = 1; i < nvpp; i++) {
xi = (double) (v + i)->x;
yi = (double) (v + i)->y;
d_xy = sqrt (SQR (xi - pvc->x) + SQR (yi - pvc->y));
if (d_xy > d_max) {
d_max = d_xy;
i_max = i;
}
if (d_xy < d_min) {
d_min = d_xy;
i_min = i;
}
}
#ifdef DEBUG
printf ("\n...d_min = %lf d_max = %lf\n", d_min, d_max);
#endif
/*
* central moments and radius of gyration
* ref: Gonzalez & Wintz, "Digital Image Processing", chapt. 8.3
*
* at the expense of efficiency, work with normalized raw moments
* where possible, to keep numbers small
*/
mu = m00;
mu11 = m11 - m00 * (m10 / m00) * (m01 / m00);
mu20 = m20 - m00 * SQR (m10 / m00);
mu02 = m02 - m00 * SQR (m01 / m00);
rad_gyr = sqrt (FABS (mu20 + mu02) / mu);
dent = FABS (((mu02 / mu20) - 1.0));
printf ("\ncentral moments:\n");
printf ("...mu00 = %lf\n", mu);
printf ("...mu11 = %lf mu20 = %lf mu02 = %lf\n", mu11, mu20, mu02);
printf ("...radius of gyration: %lf\n", rad_gyr);
printf ("...(mu02 - mu20)/mu20 = %lf\n", dent);
if ((dent < DENT_CUTOFF) && (FABS (mu11) < MU11_EPS)) {
circle = ON;
printf ("\n--->circle!!\n");
}
/*
* invariant moments
* (reference: Gonzalez & Wintz, "Digital Image Processing", chapt. 8.3)
*/
musq = SQR (mu);
phi_1 = (mu20 + mu02) / musq;
phi_2 = SQR ((mu20 - mu02) / musq) + 4.0 * SQR (mu11 / musq);
printf ("\ninvariant moments:\n");
printf ("...phi_1 = %lf phi_2 = %lf\n", phi_1, phi_2);
/*
* determine principal axes
* ref: A. Rosenfeld, A. C. Kak, "Digital Picture Processing", vol.II
*/
mu02_div_mu20 = mu02 / mu20;
tg_tth = 2.0 * (mu11 / mu20) / (1.0 - mu02_div_mu20);
printf ("\n...tg_tth = %lf\n", tg_tth);
/*
* check limits
*/
if (FABS (tg_tth) < 0.01) {
if (FABS (mu20) / FABS (mu02) >= 1.0)
horizontal = ON;
if (FABS (mu20) / FABS (mu02) <= 1.0)
vertical = ON;
}
if ((circle == ON) || (horizontal == ON) || (vertical == ON)) {
printf ("\n...circle = %d", circle);
printf ("...horizontal = %d", horizontal);
printf ("...vertical = %d", vertical);
printf ("\n-->principal axes along screen coordinate system\n");
if ((circle == ON) || (horizontal == ON)) {
x_major = d_min + (double) pvc->x;
y_major = (double) pvc->y;
x_minor = (double) pvc->x;
y_minor = d_min + (double) pvc->y;
tg_th1 = ZERO;
tg_th2 = TANGENT_LIMIT;
}
else if (vertical == ON) {
x_major = (double) pvc->x;
y_major = d_min + (double) pvc->y;
x_minor = d_min + (double) pvc->x;
y_minor = (double) pvc->y;
tg_th1 = TANGENT_LIMIT;
tg_th2 = ZERO;
}
}
else {
sq_root = sqrt (1.0 + 1.0 / SQR (tg_tth));
/*
* determine proper direction of principal (major) axis
* (sign of tg_th1, below):
* -->check whether mu11 has same or opposite sign as do mu20 and m02
*/
if (SIGN (mu20) * SIGN (mu02) < ZERO) {
printf ("\n...mu20, mu02 differ in sign");
printf (" -->something wrong?\n");
}
if ((mu11mu20_sign = SIGN (mu11) * SIGN (mu20)) > ZERO) {
quad_IV = ON; /* quadr II->IV */
if (mu02_div_mu20 <= 1.0)
tg_tth = -FABS (tg_tth);
else
tg_tth = FABS (tg_tth);
tg_th1 = (-1.0 / tg_tth) - sq_root;
tg_th2 = (-1.0 / tg_tth) + sq_root;
}
else if (mu11mu20_sign < ZERO) {
quad_I = ON; /* quadr III->I */
if (mu02_div_mu20 <= 1.0)
tg_tth = FABS (tg_tth);
else
tg_tth = -FABS (tg_tth);
tg_th1 = (-1.0 / tg_tth) + sq_root;
tg_th2 = (-1.0 / tg_tth) - sq_root;
}
else
printf ("\n...unknown condition encountered\n");
printf ("\nprincipal axes:\n");
printf ("...tg_tth = %lf tg_th1 = %lf tg_th2 = %lf\n",
tg_tth, tg_th1, tg_th2);
/*
* determine coordinates of endpoints of line segments (of length
* d_min and 0.5*d_min) to be drawn in direction of principal axes
*/
x_major = d_min / sqrt (1.0 + SQR (tg_th1));
x_minor = 0.5 * d_min / sqrt (1.0 + SQR (tg_th2));
if (quad_I == ON) {
y_major = (double) pvc->y - FABS (tg_th1) * x_major;
y_minor = (double) pvc->y + FABS (tg_th2) * x_minor;
}
if (quad_IV == ON) {
y_major = (double) pvc->y + FABS (tg_th1) * x_major;
y_minor = (double) pvc->y - FABS (tg_th2) * x_minor;
}
x_major += (double) pvc->x;
x_minor += (double) pvc->x;
}
printf ("\n...x_major = %lf y_major = %lf\n", x_major, y_major);
printf ("...x_minor = %lf y_minor = %lf\n", x_minor, y_minor);
/*
* mark principal axis directions
*/
draw_line (pvc->x, pvc->y, (int) x_major, (int) y_major, imgIO, value);
draw_line (pvc->x, pvc->y, (int) x_minor, (int) y_minor, imgIO, value);
/*
* save paramters related to moments for later reference
*/
*(moments + 0) = (float) SAVE_MOMENTS;
*(moments + 1) = (float) m00;
*(moments + 2) = (float) m10;
*(moments + 3) = (float) m01;
*(moments + 4) = (float) m11;
*(moments + 5) = (float) m20;
*(moments + 6) = (float) m02;
*(moments + 7) = (float) mu11;
*(moments + 8) = (float) mu20;
*(moments + 9) = (float) mu02;
*(moments + 10) = (float) dent;
*(moments + 11) = (float) phi_1;
*(moments + 12) = (float) phi_2;
*(moments + 13) = (float) tg_th1;
*(moments + 14) = (float) tg_th2;
return (pvc);
}